package resources.factories;

import java.lang.reflect.InvocationTargetException;
import java.util.HashMap;
import java.util.Map;
import java.util.ResourceBundle;
import java.util.Map.Entry;

import core.molecules.IMolecule;
import core.molecules.atoms.Atom;



/**
 * Basic structure of a factory for implementing IMolecule. interfaces with the format of the factories properties
 * document. all information on factory information is within that document
 * @author Julian
 *
 * @param <T>
 */
public abstract class MoleculeFactory<T extends IMolecule> {

	/**
	 * The prefix found in the key of the resource document that determines if a part of the resource file is essential to this library
	 */
	String myPrefix;
	protected Map<String[], Class<? extends T>> myMolecules;
	private static final String DELIMITER = ".";
	
	
	
	MoleculeFactory(String dir, ResourceBundle rb){
		myPrefix = dir;
		myMolecules = new HashMap<String[], Class<? extends T>>();
		try {
			assembleLibrary(rb);
		} catch (ClassNotFoundException e) {
			e.printStackTrace();
		}
	}
	
	/**
	 * Assembles the library (the map) based on the data within the resource bundle
	 * @param rb
	 * @throws ClassNotFoundException
	 */
	@SuppressWarnings("unchecked")
	public void assembleLibrary(ResourceBundle rb) throws ClassNotFoundException {
		
		String dir = rb.getString(myPrefix + ".dir");
		
		for (String key: rb.keySet()){
			if (key.startsWith(myPrefix) && !key.substring(key.lastIndexOf(DELIMITER)+1).equals("dir")){
				
				Class<? extends T> clazz = (Class<? extends T>) Class.forName(dir + key.substring(myPrefix.length()));
				myMolecules.put(rb.getString(key).split(","), clazz);
			}
			
			
		}
	}
	
	/**
	 * Creates a new molecule of the type corresponding to the input string abbreviation and with all of the arguments that follow passed
	 * into the construct method. 
	 * @param <S>
	 * @param string
	 * @param args
	 * @return
	 */
	public <S extends T> S newMoleculeByAbbr(String string, Object ... args) {
		
		for(Entry<String[], Class<? extends T>> entry : myMolecules.entrySet()){
			for(String s : entry.getKey()){
				if (string.equals(s))
					try {
						return construct(entry.getValue(), args);
					} catch (Exception e) {
						e.printStackTrace();
						throw new RuntimeException();
					}
			}
		}
		
		return null;
	}

	protected abstract <S extends T> S construct(Class<? extends T> value, Object[] args) throws IllegalArgumentException, SecurityException, InstantiationException, IllegalAccessException, InvocationTargetException, NoSuchMethodException;

	
}
